using System.Text;
using Lemon.BackgroundJobs.Abstractions;
using Lemon.BackgroundJobs.Abstractions.PublishSubscribe;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;

namespace Lemon.BackgroundJobs.RabbitMQ.PublishSubscribe;

public class PublishSubscribe : IPublishSubscribe
{
    private IRabbitMQClient _rabbitMqClient;

    public PublishSubscribe(IRabbitMQClient rabbitMqClient)
    {
        _rabbitMqClient = rabbitMqClient;
    }

    /// <summary>
    /// 发布消息(发布订阅模式)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="client"></param>
    /// <param name="msg"></param>
    /// <param name="exchange"></param>
    public void Publish<T>(T msg, string exchange) where T : class, new()
    {
        using (var channel = _rabbitMqClient.GetConnection().CreateModel())
        {
            channel.ExchangeDeclare(exchange: exchange, type: ExchangeType.Fanout, false, false, null);

            var message = Newtonsoft.Json.JsonConvert.SerializeObject(msg);
            var body = Encoding.UTF8.GetBytes(message);
            channel.BasicPublish(exchange: exchange,
                routingKey: "",
                false,
                basicProperties: null,
                body: body);
        }
    }

    /// <summary>
    /// 订阅消息(发布订阅模式)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="client"></param>
    /// <param name="exchange"></param>
    /// <param name="handler"></param>
    public void Subscribe<T>(string exchange, Action<T> handler)
        where T : class, new()
    {
        var channel = _rabbitMqClient.GetConnection().CreateModel();
        channel.ExchangeDeclare(exchange: exchange, type: ExchangeType.Fanout, false, false, null);

        var queueName = channel.QueueDeclare().QueueName;
        channel.QueueBind(queue: queueName,
            exchange: exchange,
            routingKey: "");

        var consumer = new EventingBasicConsumer(channel);
        consumer.Received += (model, ea) =>
        {
            var body = ea.Body.ToArray();
            var message = Encoding.UTF8.GetString(body);
            var msg = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(message);

            if (msg == null)
            {
                throw new Exception("message is null");
            }
            handler(msg);
        };
        channel.BasicConsume(queue: queueName,
            autoAck: true,
            consumer: consumer);
    }
}